/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.utils;

import java.util.*;
import java.io.Serializable;
import java.io.*;
import java.sql.*;

public class VectorString implements Serializable {
	private String delimiter = ",";
	private Vector store=new Vector();

	public VectorString() {}

	public VectorString(Enumeration e) {
		while (e.hasMoreElements()) {
			add(e.nextElement().toString());
		}
	}
	
	public VectorString(Object values[]) {
		for (int i = 0;i < values.length;i++) {
			add(values[i].toString());
		}
	}

	public VectorString(String values[]) {
		for (int i = 0;i < values.length;i++) {
			add(values[i]);
		}
	}
	
	public VectorString(Properties properties) {
		add(properties);
	}

	public VectorString copy() {
		VectorString copy = new VectorString();
		for (int i =0;i < size();i++) {
			copy.add(get(i));
		}
		return copy;
	}

	public void add(Properties properties) {
		Enumeration e = properties.propertyNames();
		for (;e.hasMoreElements();) {
			String key = (String) e.nextElement();
			add(key + "="+properties.get(key));
		}
	}

	/**
	 * Union adds all the performs a ? operation on the two VectorString
	 * Union adds all the strings that Exists In vs And Not In This    
	 */
	public void union(VectorString vs) {
		for (int i = 0;i < vs.size();i++) {
			if (!contains(vs.get(i))) {
				add(get(i));
			}
		}
	}

	public VectorString(StringTokenizer tokenizer) {
		for (int i = 0;i < tokenizer.countTokens();i++) {
			store.add(tokenizer.nextToken());
		}
	}

	public VectorString(String stream,String delimiter) {
		while (stream.indexOf(delimiter) != -1) {
			String data = stream.substring(0,stream.indexOf(delimiter));
			if (data.length() == 0)
				add((String)null);
			else
				add(data);
			stream = stream.substring(stream.indexOf(delimiter)+delimiter.length());
			if (stream.equals(""))
				add((String)null);
		}
		if (stream.length() > 0) add(stream);
	}

	/**
	 * Creates a new vector string fom 
	 */
	public VectorString(String stream,VectorString delimiter) {
		for (
		   String occur = delimiter.getOccurInString(stream);
		   occur != null;
		   occur = delimiter.getOccurInString(stream)
		) {
			String data = stream.substring(0,stream.indexOf(occur));
			if (data.length() == 0) {
				add((String)null);
			} else {
				add(data);
			}
			stream = stream.substring(stream.indexOf(occur)+occur.length());
			if (stream.equals("")) {
				add((String)null);
			}
		}
		if (stream.length() > 0) add(stream);
	}

	public VectorString(ResultSet rs,int col)
	throws SQLException {
		while (rs.next()) {
			add(rs.getString(col));
		}
	}

	public VectorString(ResultSet rs,String col)
	throws SQLException {
		while (rs.next()) {
			add(rs.getString(col));
		}
	}

	/**
	 * This will create a VectorString from source
	 * substringed by the del
	 */
	public VectorString(String source,int del) {
		for (;source.length() > 0;) {
			if (source.length() > del) {
				add(source.substring(0,del));
				source = source.substring(del);
			} else {
				add(source.substring(0,source.length()));
				source = "";
			}
		}
	}

	public void removeNumbers() {
		for (int i =0;i < size();i++) {
			try {
				if (get(i) != null) {
					Double.parseDouble(get(i));
					remove(i--);
				}
			} catch (Exception exception) {}
		}
	}

	public void replaceAll(String find_str,String replace,int col) {
		if (size() > col && get(col) != null && get(col).equals(find_str)) {
			set(col,replace);
		}
	}

	public void replaceAll(String find_str,String replace) {
		for (int i = 0;i < size();i++) {
			if (get(i) != null && get(i).equals(find_str)) {
				set(i,replace);
			}
		}
	}

	public void insertAtBeginOfRow(String s) {
		for (int i =0;i < size();i++) {
			set(i,s+get(i));
		}
	}

	public void insertAtEndOfRow(String s) {
		for (int i =0;i < size();i++) {
			set(i,get(i)+s);
		}
	}

	/**
	 * THIS TAKES THE FIRST VS AND SUBTRACTS ALL THE VALUES IN THE SECOND VS
	 */
	public static VectorString minus(VectorString all,VectorString exclude) {
		VectorString vs = new VectorString();
		for (int i = 0;i < all.size();i++) {
			if (!exclude.contains(all.get(i))) {
				vs.add(all.get(i));
			}
		}
		return vs;
	}

	public VectorString minus(VectorString exclude) {
		return minus(this,exclude);
	}

	public String [] toArray() {
		String values [] = new String[size()];
		for (int i =0;i < size();i++) {
			values[i] = get(i);
		}
		return values;
	}

	public String get(int pos){
		return (String)store.get(pos);
	}

	public void set(int i,String str) {
		store.set(i,str);
	}

	public void add(String item){
		store.add(item);
	}

	public void add(int index,String item){
		store.add(index,item);
	}

	public void add(VectorString vs) {
		for (int i =0;i < vs.size();i++) {
			add(vs.get(i));
		}
	}

	public void removeNull() {
		for (int i =0;i < size();i++) {
			if (get(i) == null) {
				remove(i--);
			}
		}
	}

	public boolean remove(String item){
		return store.remove(item);
	}

	public void remove(VectorString vs) {
		for (int i = 0;i < vs.size();i++) {
			remove(vs.get(i--));
		}
	}

	public void removeIgnoreCase(VectorString vs) {
		for (int i = 0;i < vs.size();i++) {
			for (int e = 0;e < size();e++) {
				if (get(e).equalsIgnoreCase(vs.get(i))) {
					remove(e--);
				}
			}
		}
	}

	public void removeWordsWithIndexOf(String index) {
		for (int i = 0;i < size();i++) {
			if (get(i).indexOf(index)!=-1) {
				remove(i--);
			}
		}
	}

	public String remove(int pos){
		return (String) store.remove(pos);
	}

	public void clear() {
		store.clear();
	}

	public int size(){
		return store.size();
	}

	public boolean contains(String value) {
		return store.contains(value);
	}

	public boolean containsIgnoreCase(String value) {
		for (int i = 0;i < size();i++) {
			if (get(i).equalsIgnoreCase(value)) {
				return true;
			}
		}
		return false;
	}

	public void trim() {
		for (int i =0;i < size();i++) set(i,get(i).trim());
	}

	public void trimBothSides() {
		for (int i =0;i < size();i++) {
			if (get(i) != null) {
				set(i,get(i).trim());
			}
			for (int e = 0;get(i) != null && e < get(i).length() && get(i).toCharArray()[e]==' ';e++) {
				set(i,get(i).substring(1));
			}
		}
	}

	public String buildNewStringFromPositionSeperatedBy(int pos,String p_del) {
		String str = "";
		for (int i = pos;i < store.size();i++) {
			str += get(i) + p_del;
		}
		if (str.length() >= p_del.length()) {
			return str.substring(0,str.length() - p_del.length());
		} else {
			return str;
		}
	}

	public String buildNewStringFromPosition(int pos) {
		return buildNewStringFromPositionSeperatedBy(pos,"");
	}

	public VectorString startsWith(String starts_with) {
		VectorString vs = new VectorString();
		for (int i =0;i < size();i++) {
			if (get(i).startsWith(starts_with)) {
				vs.add(get(i));
			}
		}
		return vs;
	}

	/**
	 * This splits VectorString into multiple VectorString from String's starting with starts_with
	 */
	public VectorString[] splitStartsWith(String starts_with) {
		Vector split = new Vector();
		for (int i = 0;i < size();i++) {
			if (get(i) != null && get(i).startsWith(starts_with)) {
				VectorString vs = new VectorString();
				vs.add(get(i));
				split.add(vs);
			} else if (get(i) != null && split.size() > 0) {
				((VectorString) split.get(split.size()-1)).add(get(i));
			}
		}
		VectorString splits[] = new VectorString[split.size()];
		for (int i = 0;i < splits.length;i++) {
			splits[i] = (VectorString) split.get(i);
		}
		return splits;
	}

	public String toString(String delim) {
		String buff = "";
		for (int i = 0;i < size();i++) {
			buff += get(i)+delim;
		}
		if (buff.length() > 0) {
			buff = buff.substring(0,buff.length()-delim.length());
		}
		return buff;
	}

	public String toString() {
		return toString(",");
	}

	public void readLines(String stream)
	throws IOException {
		stream = Utils.replaceAll(stream,"\r","\n");
		stream = Utils.replaceAll(stream,"\n\n","\n");
		LineNumberReader reader = new LineNumberReader(new InputStreamReader(new ByteArrayInputStream(stream.getBytes())));
		for (String line = reader.readLine();line != null;line = reader.readLine())
			add(line);
	}

	public void stripOutEmptyFields() {
		for (int i = 0;i < size();i++) {
			if (get(i) == null || get(i).length() == 0)
				remove(i--);
		}
	}


	/**
	 * Determines if any of VectorString values is in the given string
	 */
	public int inverseContains(String value) {
		for (int i = 0;i < size() && value != null;i++) {
			if (value.indexOf(get(i))!=-1) {
				return value.indexOf(get(i));
			}
		}
		return -1;
	}

	public int inverseContainsRemoveQuote(String value,String quote) {
		for (int i = 0;i < size() && value != null;i++) {
			if (Utils.removeDataInside(value,quote).indexOf(get(i))!=-1) {
				return value.indexOf(get(i));
			}
		}
		return -1;
	}

	public String inverseContainsName(String value) {
		for (int i = 0;i < size() && value != null;i++) {
			if (value.indexOf(get(i))!=-1)
				return get(i);
		}
		return null;
	}

	/**
	 * Finds the position of the occurrence
	 */
	public int indexOf(String occurence) {
		for (int i = 0;i < size();i++) {
			if (get(i).equals(occurence)) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * If a string inside VectorString contains an index of occurrence !=-1
	 * that will be returned
	 */
	public String getIndexOfPartial(String occurence) {
		for (int i = 0;i < size();i++) {
			if (get(i).indexOf(occurence)!=-1) {
				return get(i);
			}
		}
		return null;
	}

	/**
	 * Gets the occurent of this vector string inside the string 
	 */
	public String getOccurInString(String string) {
		int first_index = 9999;
		String occur = null;
		for (int i = 0;i < size();i++) {
			if (string.indexOf(get(i))!=-1 && string.indexOf(get(i)) < first_index) {
				occur = get(i);
				first_index = string.indexOf(get(i));
			}
		}
		return occur;
	}

	public int indexOfIgnoreCase(String occurence) {
		for (int i = 0;i < size();i++) {
			if (get(i).equalsIgnoreCase(occurence)) {
				return i;
			}
		}
		return -1;
	}

	public void removeDuplicates() {
		int cnt = 0;
		for (int e = 0;e < size();e++) {
			for (int i = 0;i < size();i++) {
				if (i != e) {
					if (get(e).equals(get(i))) {
						cnt++;
						remove(i--);
					}
				}
			}
		}
	}

	public boolean equals(Object object) {
		if (object instanceof VectorString) {
			if (((VectorString)object).size() == size()) {
				for (int i = 0;i < size();i++) {
					if (!((VectorString)object).contains(get(i))) {
						return false;
					}
				}
				return true;
			}
		}
		return false;
	}

	public boolean equalsIgnoreCase(VectorString object) {
		if (((VectorString)object).size() == size()) {
			for (int i = 0;i < size();i++) {
				if (!object.containsIgnoreCase(get(i))) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * Creates a new VectorString from position index
	 */
	public VectorString substring(int start,int end) {
		VectorString vs = new VectorString();
		for (int i =start;i < size() && i < end;i++) {
			vs.add(get(i));
		}
		return vs;
	}
	
	public VectorString substring(int start) {
		return substring(start,size());
	}

	private static boolean trimTooLong(VectorVectorString vvs,String delimiter,int length) {
		for (int i = 0;i < vvs.size();i++) {
			if (vvs.get(i).toString(delimiter).length() > length) {
				return true;
			}
		}
		return false;
	}

	private VectorVectorString trim(VectorVectorString vvs,String delimiter,int length) {
		for (;trimTooLong(vvs,delimiter,length);) {
			for (int i = 0;i < vvs.size();i++) {
				if (vvs.get(i).toString(delimiter).length() > length) {
					if (vvs.size()-1 == i) {
						vvs.add(new VectorString());
					}
					vvs.get(i+1).add(vvs.get(i).remove(vvs.get(i).size()-1));
				}
			}
		}
		return vvs;
	}

	public VectorVectorString trim(String delimiter,int length) throws BindException {
		for (int i = 0;i < size();i++) {
			if ((get(i)+delimiter).length() > length) {
				throw new BindException("Could not trip vector string. Contained string ["+get(i)+"] is larger than length ["+length+"]");
			}
		}
		VectorVectorString vvs = new VectorVectorString();
		vvs.add(copy());
		return trim(vvs,delimiter,length);
	}

	public static void main(String args[]) throws Exception {
		Log.info.out(new VectorString("hello = jasper < 12",new VectorString(new String[]{" ","=","<"})).toString(","));
	}

}

